/**
******************************************************************************
* @file           : studio_proj_c.h
* @author         : wangyingjie
* @brief          : 经纬度 转 高斯投影，墨卡托投影，地心地固直角坐标系 C 语言版
 *                : 中央经线计算公式： double central = (int)(lon / 3) * 3;
* @attention      : None
* @date           : 2025/5/9
******************************************************************************
*/

#ifndef STUDIO_PROJ_C_H
#define STUDIO_PROJ_C_H

#include <math.h>

#define AO_M_PI		3.14159265358979323846	/* pi */
#define DEG2RAD_C(deg) ((deg) * AO_M_PI / 180.0)
#define RAD2DEG_C(rad) ((rad) * 180.0 / AO_M_PI)

#define WGS84_A_C 6378137.0                                     // 长半轴
#define INVF_C 298.257223563                                    // 扁率的倒数
#define WGS84_B_C 6356752.3142                                  // 短半轴
#define WGS84_F_C 1 / INVF_C                                    // 扁率
#define WGS84_E2_C ((2 * WGS84_F_C) - (WGS84_F_C * WGS84_F_C))  // 第一偏心扁率的平方


/* 中央经线计算规范说明 ------------------------------------------------------
 * + 3度分带法 (适用于1:1万~1:50万地图)
 *   - 理论:  3度带中央经线=3度带带号*3.0 , 带号= 3度带带号=(经度+1.5°)/3取整
 *   - 带号计算: int zone_num = floor((经度 + 1.5°) / 3.0);
 *   - 中央经线: double central = floor((经度 + 1.5°) / 3.0) * 3.0;
 *
 * + 6度分带法 (适用于1:1万以下小比例地图)
 *   - 理论:  6度带中央经线=6度带带号*6.0 - 3.0 , 带号= 6度带带号=(经度+6°)/6取整
 *   - 带号计算: zone_num = floor((经度 + 6°) / 6.0);
 *   - 中央经线: double central = floor((经度 + 6°) / 6.0) * 6.0 - 3.0;
 * ----------------------------------------------------------------*/


/// 经纬度 转 高斯克吕格投影
/// \param central 中央经线 (度)
/// \param lon 经度 (度)
/// \param lat 纬度 (度)
/// \param gx 高斯坐标  x(m)
/// \param gy 高斯坐标 y(m)
void lonlat_to_gauss(const double central, const double lon, const double lat, double *gx, double *gy);

/// 高斯克吕格投影 转 经纬度
/// \param central 中央经线 (度)
/// \param gx 高斯坐标  x(m)
/// \param gy 高斯坐标 y(m)
/// \param lon 经度 (度)
/// \param lat 纬度 (度)
void gauss_to_lonlat(const double central, const double gx, const double gy, double *lon, double *lat);

/// 经纬度 转 墨卡托投影
/// \param lon 经度 (度)
/// \param lat 纬度 (度)
/// \param mctx 墨卡托投影 x(m)
/// \param mcty 墨卡托投影 y(m)
void lonlat_to_mercator(const double lon, const double lat, double *mctx, double *mcty);

/// 墨卡托投影 转 经纬度
/// \param mctx 墨卡托投影 x(m)
/// \param mcty 墨卡托投影 y(m)
/// \param lon 经度 (度)
/// \param lat 纬度 (度)
void mercator_to_lonlat(const double mctx, const double mcty, double *lon, double *lat);

/// 墨卡托投影 转 高斯投影
/// \param central 中央经线 (度)
/// \param gx 墨卡托投影 x(m)
/// \param gy 墨卡托投影 y(m)
/// \param mctx 高斯投影 x(m)
/// \param mcty 高斯投影 y(m)
void gauss_to_mercator(const double central, const double gx, const double gy, double *mctx, double *mcty);

/// 高斯投影 转 墨卡托投影
/// \param central 中央经线 (度)
/// \param mctx 墨卡托投影 x(m)
/// \param mcty 墨卡托投影 y(m)
/// \param gx 高斯投影 x(m)
/// \param gy 高斯投影 y(m)
void mercator_to_gauss(const double central, const double mctx, const double mcty, double *gx, double *gy);

/// 经纬坐标系 转 地心地固直角坐标系
/// \param lon 经度 (度)
/// \param lat 纬度 (度)
/// \param height 高程 (m)
/// \param x 地心地固直角坐标系 x (m)
/// \param y 地心地固直角坐标系 y (m)
/// \param z 地心地固直角坐标系 z (m)
void lonlat_to_ecef(const double lon, const double lat, const double height, double *x, double *y, double *z);

/// 经纬坐标系 转 地心地固直角坐标系
/// \param x 地心地固直角坐标系 x (m)
/// \param y 地心地固直角坐标系 y (m)
/// \param z 地心地固直角坐标系 z (m)
/// \param lon 经度 (度)
/// \param lat 纬度 (度)
/// \param height 高程 (m)
void ecef_to_lonlat(const double x, const double y, const double z, double *lon, double *lat, double *height);

#endif  // STUDIO_PROJ_C_H
